/*
 * Copyright (c) 2016 zhangcm. All Rights Reserved.
 */
package com.jnzc.ocr.serv.shop.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jnzc.ocr.common.bean.PageResult;
import com.jnzc.ocr.common.error.BusinessException;
import com.jnzc.ocr.common.utils.*;
import com.jnzc.ocr.dependencies.serv.mybatis.MybatisServiceImpl;
import com.jnzc.ocr.dependencies.serv.utils.MybatisUtils;
import com.jnzc.ocr.serv.shop.consts.ShopDictConsts;
import com.jnzc.ocr.serv.shop.consts.ShopMarketingPlanConsts;
import com.jnzc.ocr.serv.shop.consts.ShopMarketingTypeConsts;
import com.jnzc.ocr.serv.shop.entity.*;
import com.jnzc.ocr.serv.shop.filter.ShopMarketingPlanFilter;
import com.jnzc.ocr.serv.shop.mapper.ShopMarketingPlanMapper;
import com.jnzc.ocr.serv.shop.service.*;
import com.jnzc.ocr.serv.shop.vo.ShopMarketingPlanSelectResultVo;
import com.jnzc.ocr.serv.shop.vo.ShopMarketingPlanSelectVo;
import com.jnzc.ocr.serv.shop.vo.ShopMarketingPlanSelectedVo;
import com.jnzc.ocr.serv.shop.vo.ShopProductSkuVo;
import com.jnzc.ocr.serv.system.api.SysDictApi;
import com.jnzc.ocr.serv.system.vo.DictPair;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * @author zhangcm
 * @version 1.0, 2017/9/13
 */
@Service
public class ShopMarketingPlanServiceImpl extends MybatisServiceImpl<ShopMarketingPlanMapper, ShopMarketingPlan, ShopMarketingPlanFilter> implements ShopMarketingPlanService {

    @Autowired
    private ShopMarketingPlanMapper shopMarketingPlanMapper;

    @Autowired
    private ShopProductCategoryService shopProductCategoryService;

    @Autowired
    private ShopMemberCategoryService shopMemberCategoryService;

    @Autowired
    private SysDictApi sysDictApi;

    @Autowired
    private ShopMemberService shopMemberService;

    @Autowired
    private ShopProductSkuService shopProductSkuService;

    @Autowired
    private ShopProductService shopProductService;

    @Autowired
    private ShopMarketingRuleService shopMarketingRuleService;

    @Override
    protected void fillEntityWrapper(EntityWrapper<ShopMarketingPlan> ew, ShopMarketingPlanFilter filter) {
        ShopMarketingPlan entity = new ShopMarketingPlan();
        entity.setId(filter.getId());
        entity.setShopId(filter.getShopId());
        entity.setProductCategoryId(filter.getProductCategoryId());
        entity.setState(filter.getState());
        ew.setEntity(entity);
        if(CollectionUtils.isNotEmpty(filter.getMarketingTypeList())) {
            ew.in("marketing_type", filter.getMarketingTypeList());
        }
        if(null != filter.getNullProductCategoryId()) {
            if(filter.getNullProductCategoryId()){
                ew.isNull("product_category_id");
            } else {
                ew.isNotNull("product_category_id");
            }
        }
        if(null != filter.getMemberCategoryIdWithNull()) {
            ew.and("(member_category_id is null or member_category_id = {0})", filter.getMemberCategoryIdWithNull());
        }
        if(null != filter.getNullMemberCategoryId()) {
            if(filter.getNullMemberCategoryId()){
                ew.isNull("member_category_id");
            } else {
                ew.isNotNull("member_category_id");
            }
        }
        if(null != filter.getNowDate()) {
            ew.and("(start_term is null or start_term <= {0} )", filter.getNowDate());
            ew.and("(end_term is null or end_term >= {0} )", filter.getNowDate());
        }
    }

    @Override
    public ShopMarketingPlan find(Long id, Long shopId) {
        ValidateUtils.isId(id, "营销方案ID");
        ShopMarketingPlanFilter filter = new ShopMarketingPlanFilter();
        filter.setId(id);
        filter.setShopId(shopId);
        return super.findNotNull(filter);
    }

    @Override
    public ShopMarketingPlan save(ShopMarketingPlan obj) {
        ValidateUtils.isId(obj.getShopId(), "店铺ID");
        ValidateUtils.notEmpty(obj.getName(), 20, "店铺名称");
        ValidateUtils.notNull(obj.getMarketingType(), "营销类型");
        ValidateUtils.notNull(obj.getStartTerm(), "开始优惠时段");
        ValidateUtils.notNull(obj.getEndTerm(), "结束优惠时段");
        if(null == obj.getMarketingTypeName()){
            DictPair dictPair = sysDictApi.findPair(ShopDictConsts.SHOP_MARKETING_TYPE, obj.getMarketingType());
            obj.setMarketingTypeName(dictPair.getName());
        }
        if(null == obj.getProductCategoryId()){
            obj.setProductCategoryName(null);
        } else if(null == obj.getProductCategoryName()){
            ShopProductCategory productCategory = shopProductCategoryService.find(obj.getProductCategoryId(), obj.getShopId());
            obj.setProductCategoryName(productCategory.getName());
        }
        if(null == obj.getMemberCategoryId()){
            obj.setMemberCategoryName(null);
        } else if(null == obj.getMemberCategoryName()){
            ShopMemberCategory memberCategory = shopMemberCategoryService.find(obj.getMemberCategoryId(), obj.getShopId());
            obj.setMemberCategoryName(memberCategory.getName());
        }
        if(null == obj.getState()){
            obj.setState(ShopMarketingPlanConsts.STATE_NORMAL);
        }
        if(null == obj.getId()){
            obj.setCreateTime(DateUtils.getNow());
            shopMarketingPlanMapper.insert(obj);
        } else {
            shopMarketingPlanMapper.updateById(obj);
        }
        return obj;
    }

    @Override
    public void delete(Long id) {
        shopMarketingPlanMapper.deleteById(id);
    }

    @Override
    public Map<String, ShopMarketingPlanSelectResultVo> selectPlan(ShopMarketingPlanSelectVo selectVo, Long shopId) {
        Map<String, ShopMarketingPlanSelectResultVo> result = Maps.newHashMap();

        // 组装查询条件
        ShopMember member = null;
        if(null != selectVo.getMemberId()) {
            member = shopMemberService.find(selectVo.getMemberId(), shopId);
        }
        ShopMarketingPlanFilter filter = new ShopMarketingPlanFilter();
        filter.setShopId(shopId);
        filter.setMarketingTypeList(ShopMarketingPlanConsts.RULE_LIST);
        if(null != member) {
            filter.setMemberCategoryIdWithNull(member.getMemberCategoryId());
        } else {
            filter.setNullMemberCategoryId(true);
        }
        filter.setNowDate(DateUtils.getDay());
        filter.setState(ShopMarketingPlanConsts.STATE_NORMAL);

        // 获取产品信息
        List<Long> skuIdList = ArrayHandleUtils.readAttrList(selectVo.getProductList(), "skuId");
        Map<Long, ShopProductSkuVo> skuVoMap = shopProductSkuService.listVoMap(skuIdList, shopId);

        // 获取营销规则
        Map<Integer, List<ShopMarketingRule>> ruleMap = shopMarketingRuleService.listMap(ShopMarketingPlanConsts.RULE_LIST, shopId);

        // 获取符合条件的所有产品营销方案
        fillAllPlan(BeanUtils.clone(filter), skuVoMap, ruleMap, selectVo, result);

        // 获取符合条件的产品分类营销方案
        fillCategoryPlan(BeanUtils.clone(filter), skuVoMap, ruleMap, selectVo, result);

        return result;
    }

    @Override
    public List<ShopMarketingPlanSelectResultVo> list(List<ShopMarketingPlanSelectedVo> voList, Long shopId) {
        List<ShopMarketingPlanSelectResultVo> result = Lists.newArrayList();
        for (ShopMarketingPlanSelectedVo vo : voList) {
            ShopMarketingPlan plan = this.find(vo.getPlanId(), shopId);
            ShopMarketingRule rule = shopMarketingRuleService.find(vo.getRuleId(), shopId);
            BusinessUtils.isTrue(plan.getMarketingType().equals(rule.getMarketingType()), "营销方案和规则类型不同");
            ShopMarketingPlanSelectResultVo obj = new ShopMarketingPlanSelectResultVo();
            obj.setPlan(plan);
            obj.setRule(rule);
            result.add(obj);
        }
        return result;
    }

    private void fillAllPlan(ShopMarketingPlanFilter filter, Map<Long, ShopProductSkuVo> skuVoMap, Map<Integer, List<ShopMarketingRule>> ruleMap, ShopMarketingPlanSelectVo selectVo, Map<String, ShopMarketingPlanSelectResultVo> result) {
        BigDecimal amount = BigDecimal.ZERO;
        for (ShopMarketingPlanSelectVo.Product productParam : selectVo.getProductList()) {
            ShopProductSkuVo skuVo = skuVoMap.get(productParam.getSkuId());
            BigDecimal addAmount = CalculateUtils.mul(skuVo.getSku().getPrice(), productParam.getNum());
            amount = CalculateUtils.add(amount, addAmount);
        }
        filter.setNullProductCategoryId(true);
        ShopMarketingPlanSelectResultVo selectResultVo = choosePlan(super.list(filter), amount, ruleMap);
        result.put(ShopMarketingPlanConsts.SELECT_ALL, selectResultVo);
    }

    private void fillCategoryPlan(ShopMarketingPlanFilter filter, Map<Long, ShopProductSkuVo> skuVoMap, Map<Integer, List<ShopMarketingRule>> ruleMap, ShopMarketingPlanSelectVo selectVo, Map<String, ShopMarketingPlanSelectResultVo> result) {
        Map<Long, BigDecimal> amountMap = Maps.newHashMap();
        for (ShopMarketingPlanSelectVo.Product productParam : selectVo.getProductList()) {
            ShopProductSkuVo skuVo = skuVoMap.get(productParam.getSkuId());
            BigDecimal addAmount = CalculateUtils.mul(skuVo.getSku().getPrice(), productParam.getNum());
            BigDecimal oldAmount = amountMap.get(skuVo.getProduct().getCategoryId());
            amountMap.put(skuVo.getProduct().getCategoryId(), CalculateUtils.add(oldAmount, addAmount));
        }

        for (Long categoryId : amountMap.keySet()) {
            BigDecimal amount = amountMap.get(categoryId);
            filter.setProductCategoryId(categoryId);
            ShopMarketingPlanSelectResultVo selectResultVo = choosePlan(super.list(filter), amount, ruleMap);
            result.put(ShopMarketingPlanConsts.SELECT_C + categoryId, selectResultVo);
        }
    }

    private ShopMarketingPlanSelectResultVo choosePlan(List<ShopMarketingPlan> planList, BigDecimal amount, Map<Integer, List<ShopMarketingRule>> ruleMap) {
        if(CollectionUtils.isEmpty(planList)) {
            return null;
        }
        ShopMarketingPlanSelectResultVo result = null;
        for (ShopMarketingPlan plan : planList) {
            ShopMarketingPlanSelectResultVo temp = chooseRule(plan, ruleMap.get(plan.getMarketingType()), amount);
            if(null != temp && null == result) {
                result = temp;
            } else if(null != temp && null != result && result.getDiscountAmount().compareTo(temp.getDiscountAmount()) < 0) {
                result = temp;
            }
        }
        return result;
    }

    private ShopMarketingPlanSelectResultVo chooseRule(ShopMarketingPlan plan, List<ShopMarketingRule> ruleList, BigDecimal amount) {
        if(CollectionUtils.isEmpty(ruleList)) {
            return null;
        }
        ShopMarketingRule temp = null;
        for (ShopMarketingRule rule : ruleList) {
            if(rule.getAmountLine().compareTo(amount) > 0) {
                break;
            }
            temp = rule;
        }
        if(null == temp) {
            return null;
        }
        ShopMarketingPlanSelectResultVo resultVo = new ShopMarketingPlanSelectResultVo();
        resultVo.setPlan(plan);
        resultVo.setRule(temp);
        if(plan.getMarketingType().equals(ShopMarketingTypeConsts.AMOUNT)) {
            resultVo.setDiscountAmount(temp.getAmount());
        } else if(plan.getMarketingType().equals(ShopMarketingTypeConsts.DISCOUNT)) {
            BigDecimal discount = CalculateUtils.sub(10, temp.getDiscount());
            resultVo.setDiscountAmount(CalculateUtils.div(CalculateUtils.mul(amount, discount), 10, 2));
        } else {
            throw new BusinessException("类型不正确");
        }
        return resultVo;
    }
}
